.pc = * "Hero Routines"

hero_pos_x:
    .word 0
hero_pos_y:
    .word 0

init_hero:
{
    :SetupSprite(0, $c4c0)
    :SetupSprite(1, $c480)
    :EnableSprite(0)
    :EnableSprite(1)
    
    lda #0
    sta hero_pos_x
    sta hero_pos_y

    lda #5
    sta hero_pos_x+1
    sta hero_pos_y+1
    
    rts
}
    
//////////////////////////////

destroy_hero:
{
    :DisableSprite(0)
    :DisableSprite(1)
    rts
}
    
//////////////////////////////

update_hero:
{
.label origin = zero_page_start // two bytes
.label old_pos_x = zero_page_start + 2 // two bytes
.label old_pos_y = zero_page_start + 4 // two bytes
.label map_addr = zero_page_start + 6 // two bytes
    
    :EnableSprite(0)
    :EnableSprite(1)

    // copy current position
    lda hero_pos_x
    sta old_pos_x
    lda hero_pos_x+1
    sta old_pos_x+1
    lda hero_pos_y
    sta old_pos_y
    lda hero_pos_y+1
    sta old_pos_y+1

    sec
    
    :TestWKey()
    bne notW
    lda hero_pos_y
    sbc #16
    sta hero_pos_y
    bcs notW
    dec hero_pos_y+1
    sec
notW:
    :TestAKey()
    bne notA
    jsr hero_face_left
    lda hero_pos_x
    sbc #16
    sta hero_pos_x
    bcs notA
    dec hero_pos_x+1
notA:
    clc
    :TestSKey()
    bne notS
    lda hero_pos_y
    adc #16
    sta hero_pos_y
    bcc notS
    inc hero_pos_y+1
    clc
notS:
    :TestDKey()
    bne notD
    jsr hero_face_right
    lda hero_pos_x
    adc #16
    sta hero_pos_x
    bcc notD
    inc hero_pos_x+1
notD:

    // hide kernel
    lda 1
    and #253
    sta 1

    // test if we stepped into something solid; move back where we were if so
    ldx hero_pos_y+1
    lda map_lookup_lobytes,x
    sta map_addr
    lda map_lookup_hibytes,x
    sta map_addr+1
    ldy hero_pos_x+1
    lda (map_addr),y
    tax
    lda tile_lookup_lobytes,x
    sta map_addr
    lda tile_lookup_hibytes,x
    sta map_addr+1
    ldy #33
    lda (map_addr),y
    and #16
    beq notSolid

    // stepped into something solid; reset position
    lda old_pos_x
    sta hero_pos_x
    lda old_pos_x+1
    sta hero_pos_x+1
    lda old_pos_y
    sta hero_pos_y
    lda old_pos_y+1
    sta hero_pos_y+1

notSolid:    
    // bring back kernel
    lda 1
    ora #2
    sta 1

    // compute screen position from world position
    lda background_origin_x
    sta origin+1
    lda background_origin_x_half
    clc
    ror
    ror
    sta origin
    sec
    lda hero_pos_x
    sbc origin
    sta origin
    lda hero_pos_x+1
    sbc origin+1
    .for (var i=0; i<4; i++)
    {
        lsr
        ror origin
    }

    // offset x coordinate by 12
    sta origin+1
    lda origin
    clc
    adc #12
    sta origin
    lda origin+1
    adc #0
    
    bne notZero
    :SetSpriteX(0, origin)
    :SetSpriteX(1, origin)

    // test for x scrolling
    lda origin
    cmp #50
    bcs doneX
    jsr background_scroll_left
    jmp doneX
notZero:
    cmp #1
    bne doneX
    :SetSpriteXPlus256(0, origin)
    :SetSpriteXPlus256(1, origin)
    lda origin
    cmp #50
    bmi doneX
    jsr background_scroll_right
doneX:
    lda background_origin_y
    sta origin+1
    lda background_origin_y_half
    clc
    ror
    ror
    sta origin
    sec
    lda hero_pos_y
    sbc origin
    sta origin
    lda hero_pos_y+1
    sbc origin+1
    .for (var i=0; i<4; i++)
    {
        lsr
        ror origin
    }

    // offset y by 32
    sta origin+1
    lda origin
    clc
    adc #32
    sta origin
    lda origin+1
    adc #0
    
    bne doneY
    :SetSpriteY(0, origin)
    :SetSpriteY(1, origin)

    // test for y scrolling
    lda origin
    cmp #60
    bcs no_up
    jsr background_scroll_up
    jmp doneY
no_up:
    cmp #210
    bcc doneY
    jsr background_scroll_down
doneY:
    rts
}

hero_face_right:
{
    :SetupSprite(0, $c4c0)
    :SetupSprite(1, $c480)
    rts
}

hero_face_left:
{
    :SetupSprite(0, $c440)
    :SetupSprite(1, $c400)
    rts
}
